#include "los_typedef.h"

#include "sdfile.h"

#include "ioctl_cmds.h"
#include "boot.h"

#include "crc16.h"
#include "sfc_norflash_api.h"
#include "vm.h"

#define SEEK_SET  0
#define SEEK_CUR  1
#define SEEK_END  2

#define F_ATTR_DIR   0x4

#if (USE_SDFILE_NEW == 1)

#ifdef SDFILE_VERSION
#define THIS_MODULE sdfile
MODULE_VERSION_EXPORT(THIS_MODULE, SDFILE_VERSION);
MODULE_DEPEND_BEGIN()
MODULE_DEPEND_END()
#endif

#define LOG_TAG             "[SDFILE]"
#define LOG_ERROR_ENABLE
/* #define LOG_INFO_ENABLE */
/* #define LOG_DEBUG_ENABLE */
#include "debug.h"

#define SDFILE_PAGE_SIZE 	256
#define SDFILE_SECTOR_SIZE 	4096

#define __PAGE(addr)   ((addr) & ~(SDFILE_PAGE_SIZE - 1))
#define __PAGE_NUM(len)   (((len) + 256 - 1) / 256)
#define __PAGE_ALIGN(len)   (((len) + 256 - 1) / 256 * 256)
#define __SECTOR_ALIGN(len)   (((len) + SDFILE_SECTOR_SIZE - 1) / SDFILE_SECTOR_SIZE * SDFILE_SECTOR_SIZE)

#define SDFILE_PART_APP 		0x55
#define SDFILE_PART_RES 		0xAA

#define SDFILE_FILE_ATTR_UBOOT 		0x00		//uboot代码文件
#define SDFILE_FILE_ATTR_APP 		0x01		//app代码文件
#define SDFILE_FILE_ATTR_REG 		0x02		//普通文件
#define SDFILE_FILE_ATTR_DIR 		0x03		//目录文件
#define SDFILE_FILE_ATTR_RESERVED 	0x10		//预留文件
#define SDFILE_FILE_ATTR_CPMPRESS 	0x40		//压缩文件
#define SDFILE_FILE_ATTR_ENC 		0x80 		//加密文件

#define SDFILE_FILE_ATTR_TYPE_MASK	0x0F

//================================================//
//                sdfile 优化编译                 //
//================================================//
extern const int SDFILE_VFS_REDUCE_ENABLE;
#define SDFILE_VFS_REDUCE_BEGIN(); \
	if (!SDFILE_VFS_REDUCE_ENABLE) {

#define SDFILE_VFS_REDUCE_END(); \
	} else { \
		return ESRCH; \
	}

#define SDFILE_VFS_REDUCE_END_V2(); \
	}

/********* sdfile全局信息  **********/
struct sdfile_handle {
    /***** flash addr *****/
    u32 sfc_base_addr; 	//sfc基地址, 即app代码开始地址(flash addr)
    //u32 vm_end_addr;  	//vm 结束地址(flash addr)
    /***** cpu logic addr ******/
    //u32 vm_begin_addr; 	//vm开始地址(cpu addr)
    //u32 flash_size; 	//flash 大小(cpu addr)
    u32 app_addr;  		//app开始地址(cpu addr)
//分区地址
    u32 app_part_addr;  //APP分区开始地址(cpu addr)
    u32 ext_res_part_addr;  //EXT_RESERVED资源分区开始地址(cpu addr)
    u32 res_part_addr;  //RES资源分区开始地址(cpu addr)
//debug
    u32 dir_addr;
    u32 vm_end_addr;
};



static struct sdfile_handle  _sdfile_handl;

#define sdfile  (&_sdfile_handl)


#if NOR_SDFILE_ENABLE
struct NOR_SDFILE_HDL {
    u32 addr_offset;  //用于获取资源文件内的文件的地址。
    s32(*read)(u8 *buf, u32 addr, u32 len);
    s32(*write)(u8 *buf, u32 addr, u32 len);
};
struct NOR_SDFILE_HDL nor_sdfile_hdl;
#endif

//static SDFILE sdfile_pool[1] = {0};


void doe(u16 k, void *pBuf, u32 lenIn, u32 addr);
int norflash_origin_read(u8 *buf, u32 offset, u32 len);
static u32 decode_data_by_user_key_in_sdfile(u16 key, u8 *buff, u16 size, u32 dec_addr, u8 dec_len)
{
    u16 key_addr;
    u16 r_len;

    while (size) {
        r_len = (size > dec_len) ? dec_len : size;
        key_addr = (dec_addr >> 2)^key;
        doe(key_addr, buff, r_len, 0);
        buff += r_len;
        dec_addr += r_len;
        size -= r_len;
    }

    return dec_addr;
}

void sdfile_head_addr_get(char *name, u32 *addr, u32 *len)
{
    u32 start_addr = boot_info.sfc.sfc_base_addr;
    u32 offset = 0;
    struct sdfile_file_head head = {0};
    u16 local_flash_key = boot_info.chip_id;
    while (1) {
        norflash_origin_read((u8 *)&head, start_addr, sizeof(head));
        decode_data_by_user_key_in_sdfile(local_flash_key, (u8 *)&head, sizeof(head), offset, sizeof(head));
        if (head.head_crc != CRC16((u8 *)&head.data_crc, sizeof(head) - sizeof(head.head_crc))) {
            y_printf("\n >>>[test]:func = %s,line= %d\n", __FUNCTION__, __LINE__);
            return;
        }
        if (0 == memcmp(head.name, name, strlen(name))) {
            break;
        }
        offset += sizeof(head);
        start_addr += sizeof(head);
    }

    {
        *addr = head.addr;
        *len = head.len;
    }
    r_printf(">>>[test]:#########  start_addr = 0x%x, len = 0x%x\n", head.addr, head.len);
}

u32 sdfile_flash_addr2cpu_addr(u32 offset)
{
    return offset - sdfile->sfc_base_addr + sdfile->app_addr;
}

u32 sdfile_cpu_addr2flash_addr(u32 offset)
{
    return offset - sdfile->app_addr + sdfile->sfc_base_addr;
}

static inline void sdfile_str_to_upper(char *str, int len)
{
    while (len--) {
        if ((*str >= 'a') && (*str <= 'z')) {
            *str = *str - 'a' + 'A';
        }
        str ++;
    }
}

static int sdfile_strcmp(char *src, char *dst, u8 len)
{
    bool star = 0;				//有没有'*'

    while (len--) {
        if (star) {
            if (*src == '.') {
                star = 0;
            }
        } else if (*src != *dst) {    //比较不相等
            if (*dst == '?') {
                return 0;
            } else if (*dst == '*') {
                star = 1;
            } else {
                return -1;
            }
        } else if (*dst == '\0') {	//同时结束
            return 0;
        }

        src++;
        dst++;
    }

    return 0;
}

static int sdfile_strcase_cmp(const char *str1, const char *str2)
{
    int ret = 0;
    char tmp_str1[SDFILE_NAME_LEN + 1] = {0};
    char tmp_str2[SDFILE_NAME_LEN + 1] = {0};

    memcpy(tmp_str1, str1, SDFILE_NAME_LEN);
    memcpy(tmp_str2, str2, SDFILE_NAME_LEN);

    sdfile_str_to_upper(tmp_str1, SDFILE_NAME_LEN);
    sdfile_str_to_upper(tmp_str2, SDFILE_NAME_LEN);

    ret = sdfile_strcmp(tmp_str1, tmp_str2, SDFILE_NAME_LEN);

    return ret;
}



static int __sdfile_get_vm_begin(void)
{
    struct sdfile_file_head *head;
    int ret = 0;

    for (head = (struct sdfile_file_head *)(sdfile->app_part_addr + sizeof(struct sdfile_file_head));
         head->index == 0; head++) {
        ret = sdfile_strcase_cmp("vm", head->name);
		printf("%s: for\n", __func__);

        if (!ret) {
            boot_info.vm.vm_saddr = head->addr;  //flash addr
            boot_info.vm.vm_size = head->len;
            printf("VM size: 0x%x @ 0x%x", head->len, head->addr);
            return SDFILE_SUSS;
        }
    }

    ASSERT(0, "vm not find");

    return SDFILE_VM_NOT_FIND;
}

/*
 * SDFILE分区：
 * 1.APP：根目录:app_area_head, 子文件：app.bin, cfg_tools.bin, VM, PRCT, BTIF, WTIF
 * 1.RES：根目录:tone或者其它, 子文件：资源子文件
 */

static int __sdfile_get_part_addr(char *name)
{
    struct sdfile_file_head head;
    u32 part_addr = sdfile->app_addr;
    if (part_addr == 0) {
        return 0;
    }

    do {
        memcpy((u8 *)&head, (u8 *)part_addr, sizeof(struct sdfile_file_head));
        if (0 != sdfile_strcase_cmp(head.name, "app_area_head") && 0 != sdfile_strcase_cmp(head.name, "EXT_RESERVED")) {
            return part_addr;
        }

        if (0 == sdfile_strcase_cmp(name, head.name)) {
            return part_addr;
        }
        part_addr += head.len;
    } while (!head.index);

    return 0;
}

static int __sdfile_get_app_part_addr(void)
{
    sdfile->app_part_addr = sdfile->app_addr;

    return 0;
}

static int __sdfile_get_res_part_addr(void)
{
    struct sdfile_file_head *app_head;
    app_head = (struct sdfile_file_head *)sdfile->app_addr;
    sdfile->res_part_addr = sdfile->app_addr + app_head->len;

    return 0;
}

static int __sdfile_get_root_last_file(u32 *addr, u32 *len)
{
    int ret = 0;
    struct sdfile_file_head head_ins;
    struct sdfile_file_head *head;

    /* u32 org_addr = sdfile->res_part_addr; */
    u32 org_addr = sdfile->app_part_addr;
    u16 calc_crc;
    do {
        memcpy((u8 *)&head_ins, (u8 *)org_addr, sizeof(struct sdfile_file_head));

        calc_crc = CRC16((u8 *)&head_ins + 2, sizeof(struct sdfile_file_head) - 2);
        if (calc_crc != head_ins.head_crc) {
            ret = -1;
            log_error("file head crc err,addr=%x\n", org_addr);
            return ret;
        }
        //	printf("name:%s\nindex:%x\naddr:%x\nlen:%x\n",head_ins.name,head_ins.index,head_ins.addr,head_ins.len);
        org_addr += head_ins.len;
    } while (head_ins.index == 0);

    if (addr) {
        *addr = sdfile_cpu_addr2flash_addr(org_addr - head_ins.len);
    }
    if (len) {
        *len = head_ins.len;
    }

    return ret;
}

#define RESERVED_FOR_BURN_SIZE	0x20
static u8 burn_code[0x10];

u8 *sdfile_get_burn_code(u8 *len)
{
    if (len) {
        *len = sizeof(burn_code);
    }

    return burn_code;
}

static int __sdfile_get_flash_bin_end_addr(u32 *addr)
{
    int ret = 0;
    u32 last_file_addr, last_file_len;

    u32 end_addr = 0;
    u16 align_size = SDFILE_SECTOR_SIZE;
    u8 burn_code_len = sizeof(burn_code);
    if (0 == __sdfile_get_root_last_file(&last_file_addr, &last_file_len)) {
        printf("last file_addr:%x %x\n", last_file_addr, last_file_len);
        if (boot_info.vm.align == 1) {
            align_size = SDFILE_PAGE_SIZE;
        }
        end_addr = (last_file_addr + last_file_len + RESERVED_FOR_BURN_SIZE);
        end_addr = (end_addr + (align_size - 1)) / align_size * align_size;

        printf("end_addr:%x\n", end_addr);
        norflash_origin_read(burn_code, end_addr - burn_code_len, burn_code_len);
        put_buf(burn_code, burn_code_len);

        if (addr) {
            *addr = end_addr;
        }
    } else {
        ret = -1;
    }

    return ret;
}

int sdfile_init(void)
{
printf("%s: entry!\n", __func__);
    int ret;
    memset(sdfile, 0, sizeof(struct sdfile_handle));
    sdfile->sfc_base_addr    = boot_info.sfc.sfc_base_addr;  //flash addr
    sdfile->app_addr         = boot_info.sfc.app_addr;   	 //cpu logic addr

    sdfile->app_part_addr = __sdfile_get_part_addr("app_area_head");
    sdfile->ext_res_part_addr = __sdfile_get_part_addr("EXT_RESERVED");
    sdfile->res_part_addr = __sdfile_get_part_addr("res");
    /* r_printf(">>>[test]:app_addr = %d, ext_res = %d, res = %d\n", sdfile->app_part_addr, sdfile->ext_res_part_addr, sdfile->res_part_addr); */
    /* __sdfile_get_app_part_addr(); */
    /* __sdfile_get_res_part_addr(); */
    ret = __sdfile_get_vm_begin();  //flash memory addr
	printf("%s: if!!!\n", __func__);

    if (ret) {
        printf("sdfile get_vm_addr err!!!\n");
        return ret;
    }
	printf("%s: norflash_open!!!\n", __func__);

    norflash_open(NULL, NULL, NULL);
    norflash_ioctl(NULL, IOCTL_SET_VM_INFO, (u32)&boot_info);
	printf("%s: sdfile_get_disk_capacity!!!\n", __func__);

    u32 cap = sdfile_get_disk_capacity();       //获取flashr大小

    printf("disk capacity %d KB\n", cap / 1024);

#ifdef CONFIG_CPU_BR23
#ifdef CONFIG_APP_WATCH
    // br23手表项目的特殊限制
    extern const u8 btstack_emitter_support;
    if (btstack_emitter_support) {
        if (cap < (2 * 1024 * 1024)) {
            printf(" flash cap limit : %d \n", cap);
            while (1);
        }
    }
#endif /* #ifdef CONFIG_APP_WATCH */
#endif /* #ifdef CONFIG_CPU_BR23 */

    __sdfile_get_flash_bin_end_addr(NULL);

#if (VFS_ENABLE == 1)
    if (mount(NULL, "mnt/sdfile", "sdfile", 0, NULL)) {
        printf("sdfile mount succ\n");
    } else {
        printf("sdfile mount failed!!!\n");
    }
#endif /* #if (VFS_ENABLE == 1) */

    return 0;
}
/* early_initcall(sdfile_init); */

//SDFILE路径:sdfile/文件名
//SDFILE路径:sdfile/目录名/文件名

static const char *__sdfile_path_get_name(const char *path_new, char *name)
{
    char *ptr;
    int len, plen;

    if (*path_new == '/') {
        path_new ++;
    }
    ptr = strchr((const char *)path_new, '/');
    if (ptr) {
        plen = ptr - path_new;
    } else {
        plen = strlen((const char *)path_new);
    }
    len = plen;
    if (len >= 16) {
        len = 16 - 1;
    }
    memcpy(name, path_new, len);
    name[len] = 0;
    sdfile_str_to_upper(name, len);
    path_new += plen;
    if (*path_new == '/') {
        path_new ++;
    }

    return path_new;
}

static int sdfile_for_each_file_in_dir(u32 org_addr, struct sdfile_file_head *ret_head, char *dest_name)
{
    u32 addr = 0;
    int err_cnt = 32;
    int ret = 0;
    struct sdfile_file_head head;

    for (addr = org_addr; err_cnt > 0; addr += sizeof(struct sdfile_file_head)) {
        memcpy((u8 *)&head, (u8 *)addr, sizeof(struct sdfile_file_head));

        if (CRC16((u8 *)&head + 2, sizeof(struct sdfile_file_head) - 2) != head.head_crc) {
            err_cnt--;
            continue;
        }
        ret = sdfile_strcase_cmp(head.name, dest_name);

        if (!ret) {
            if (ret_head) {
                memcpy((u8 *)ret_head, (u8 *)&head, sizeof(struct sdfile_file_head));
            }
            return SDFILE_SUSS;
        }

        if (head.index) {
            return SDFILE_END;
        }
    }

    return SDFILE_FILE_NOT_EXIST;
}

static int sdfile_for_each_dir(struct sdfile_file_head *dir_head, const char *dest_name)
{
    int ret;
    struct sdfile_file_head head;
    u32 addr = sdfile->res_part_addr;

    do {
        memcpy((u8 *)&head, (u8 *)addr, sizeof(struct sdfile_file_head));
        if (CRC16((u8 *)&head + 2, sizeof(struct sdfile_file_head) - 2) != head.head_crc) {
            return SDFILE_DATA_CRC_ERR;
        }

        ret = sdfile_strcase_cmp(head.name, dest_name);
        if (!ret) {
            memcpy((u8 *)dir_head, (u8 *)&head, sizeof(struct sdfile_file_head));
            dir_head->addr = addr;
            return SDFILE_SUSS;
        }

        addr += head.len;
    } while (head.index == 0);

    return SDFILE_DIR_NOT_EXIST;
}

static int sdfile_open_part_dir(struct sdfile_dir *dir, const char *dest_name, const char *part_name)
{
    int ret;
    /* ret = sdfile_for_each_dir(&(dir->head), dest_name); */
    u8 flag = 0;
    u32 addr;
    struct sdfile_file_head head;
    if (sdfile_strcase_cmp(part_name, "app_area_head") == 0) {
        addr = sdfile->app_part_addr;
    } else if (sdfile_strcase_cmp(part_name, "EXT_RESERVED") == 0) {
        addr = sdfile->ext_res_part_addr;
    } else if (sdfile_strcase_cmp(part_name, "res") == 0) {
        addr = sdfile->res_part_addr;
    } else {
        return SDFILE_DIR_NOT_EXIST;
    }
    if (dir->head.addr) {
        addr = dir->head.addr;
        addr = sdfile_flash_addr2cpu_addr(addr);
        flag = 1;
    }

    do {
        memcpy((u8 *)&head, (u8 *)addr, sizeof(struct sdfile_file_head));
        if (CRC16((u8 *)&head + 2, sizeof(struct sdfile_file_head) - 2) != head.head_crc) {
            ret = SDFILE_DATA_CRC_ERR;
            break;
        }

        /* put_buf((u8 *)&head, 32); */
        ret = sdfile_strcase_cmp(head.name, dest_name);
        if (!ret) {
            memcpy((u8 *) & (dir->head), (u8 *)&head, sizeof(struct sdfile_file_head));
            dir->head.addr = head.addr;
            if (flag) {
                dir->head.addr = addr;
            }
            ret = SDFILE_SUSS;
            break;
        }

        addr += sizeof(struct sdfile_file_head);
    } while (head.index == 0);

    return ret;
}

static int sdfile_open_dir(struct sdfile_dir *dir, const char *dest_name)
{
    int ret;
    ret = sdfile_for_each_dir(&(dir->head), dest_name);
    if (ret == SDFILE_SUSS) {
        if ((dir->head.attr & SDFILE_FILE_ATTR_TYPE_MASK) == SDFILE_FILE_ATTR_DIR) {
            ret = SDFILE_SUSS;
        } else {
            ret = SDFILE_DIR_NOT_EXIST;
        }
    }

    return ret;
}

static int sdfile_open_file_in_dir(struct sdfile_file_t *file, struct sdfile_dir *dir, char *name)
{
    int ret;

    u32 org_addr = dir->head.addr + sizeof(struct sdfile_file_head);

    ret = sdfile_for_each_file_in_dir(org_addr, &file->head, name);

    if (ret == SDFILE_SUSS) {
        if ((file->head.attr & SDFILE_FILE_ATTR_RESERVED) == SDFILE_FILE_ATTR_RESERVED) {
            //printf("res abs addr @ 0x%x", file->head.addr);
            // reserved file, absolute addr
            file->head.addr = sdfile_flash_addr2cpu_addr(file->head.addr);
        } else {
            file->head.addr += dir->head.addr;
            //printf("normal file @ 0x%x", file->head.addr);
        }
    }

    return ret;
}

static int sdfile_open_spc_part_file(struct sdfile_file_t *file, struct sdfile_dir *dir, char *name)
{
    int ret;

    u32 org_addr = dir->head.addr + sizeof(struct sdfile_file_head);

    ret = sdfile_for_each_file_in_dir(org_addr, &file->head, name);

    if (ret == SDFILE_SUSS) {
        if ((file->head.attr & SDFILE_FILE_ATTR_REG) != SDFILE_FILE_ATTR_REG) {
            ret = -1;
        }
    }

    return ret;
}

static int sdfile_open_file_in_root(struct sdfile_file_t *file, const char *dest_name)
{
    int ret;

    ret = sdfile_for_each_dir(&(file->head), dest_name);

    if (ret == SDFILE_SUSS) {
        file->head.addr += sizeof(struct sdfile_file_head);
        file->head.len -= sizeof(struct sdfile_file_head);
    }
#if NOR_SDFILE_ENABLE
    nor_sdfile_hdl.addr_offset = file->head.addr;
#endif

    return ret;
}

static int sdfile_open_app_file(SDFILE *file, const char *path)
{
    const char *path_new = path;
    char name[16 + 1] = {0};
    struct sdfile_dir dir;
    int ret = SDFILE_FILE_NOT_EXIST;

    memcpy((u8 *) & (dir.head), (u8 *)(sdfile->app_part_addr), sizeof(struct sdfile_file_head));

    dir.head.addr = sdfile->app_addr;

    path_new = __sdfile_path_get_name(path_new, name);
    if (*path_new) {
        // dir
        memset((u8 *)&dir, 0, sizeof(struct sdfile_dir));
        ret = sdfile_open_part_dir(&dir, name, "app_area_head");
        if (ret != SDFILE_SUSS) {
            return ret; //dir not exist, return
        }
        path_new = __sdfile_path_get_name(path_new, name);
        if (*path_new) {
            ret = sdfile_open_part_dir(&dir, name, "app_area_head");
            if (ret != SDFILE_SUSS) {
                return ret; //dir not exist, return
            }
            path_new = __sdfile_path_get_name(path_new, name);
            ret = sdfile_open_file_in_dir(file, &dir, name);
        } else {
            dir.head.addr = sdfile_flash_addr2cpu_addr(dir.head.addr) - sizeof(struct sdfile_file_head);
            ret = sdfile_open_spc_part_file(file, &dir, name);
        }
    } else {
        ret = sdfile_open_file_in_dir(file, &dir, name);
    }


    return ret;
}

static int sdfile_open_ext_res_file(SDFILE *file, const char *path)
{
    const char *path_new = path;
    char name[16 + 1] = {0};
    struct sdfile_dir dir;
    int ret = SDFILE_FILE_NOT_EXIST;

    memcpy((u8 *) & (dir.head), (u8 *)(sdfile->ext_res_part_addr), sizeof(struct sdfile_file_head));

    dir.head.addr = sdfile->ext_res_part_addr;

    path_new = __sdfile_path_get_name(path_new, name);
    if (*path_new) {
        // dir
        memset((u8 *)&dir, 0, sizeof(struct sdfile_dir));
        ret = sdfile_open_part_dir(&dir, name, "EXT_RESERVED");
        if (ret != SDFILE_SUSS) {
            return ret; //dir not exist, return
        }
        path_new = __sdfile_path_get_name(path_new, name);
        if (*path_new) {
            ret = sdfile_open_part_dir(&dir, name, "EXT_RESERVED");
            if (ret != SDFILE_SUSS) {
                return ret; //dir not exist, return
            }
            path_new = __sdfile_path_get_name(path_new, name);
            ret = sdfile_open_file_in_dir(file, &dir, name);
        } else {
            dir.head.addr = sdfile_flash_addr2cpu_addr(dir.head.addr) - sizeof(struct sdfile_file_head);
            ret = sdfile_open_spc_part_file(file, &dir, name);
        }
    } else {
        ret = sdfile_open_file_in_dir(file, &dir, name);
    }

    return ret;
}

static int sdfile_open_res_file(SDFILE *file, const char *path)
{
    const char *path_new = path;
    char name[16 + 1] = {0};
    struct sdfile_dir dir;
    int ret = SDFILE_FILE_NOT_EXIST;
    path_new = __sdfile_path_get_name(path_new, name);
    if (*path_new) {
        // dir
        ret = sdfile_open_dir(&dir, name);
        if (ret != SDFILE_SUSS) {
            return ret; //dir not exist, return
        }
        __sdfile_path_get_name(path_new, name);
        ret = sdfile_open_file_in_dir(file, &dir, name);
    } else {
        // file in root
        ret = sdfile_open_file_in_root(file, name);
    }

    return ret;
}

#if 0
static u32 sdfile_erase_sector(u32 addr)
{
    u32 erase_addr;  //flash addr

    u32 erase_size = SDFILE_SECTOR_SIZE;
    u32 erase_cmd = IOCTL_ERASE_SECTOR;

    if (boot_info.vm.align == 1) {
        erase_size = SDFILE_PAGE_SIZE;
        erase_cmd = IOCTL_ERASE_PAGE;
    }

    erase_addr = addr & (~(erase_size - 1));
    norflash_ioctl(NULL, erase_cmd, erase_addr);
    log_info("flash erase >>>");

    return erase_addr;
}
#endif

static int sdfile_write_area_check(u8 *wbuf, u32 addr, u32 len)
{
#if 0
    u32 i = 0;
    u32 offset = addr;
    u32 end_addr = addr + len;
    u8 *buf = 0;
    u32 remain_len = len;
    u32 rlen = 0;

    u32 erase_size = SDFILE_SECTOR_SIZE;

    if (boot_info.vm.align == 1) {
        erase_size = SDFILE_PAGE_SIZE;
    }

    do {
        buf = (u8 *)sdfile_flash_addr2cpu_addr(offset);  //to cpu logic addr
        remain_len -= rlen;
        rlen = remain_len > erase_size ? erase_size : remain_len;
        for (i = 0; i < rlen; i++) {
            if ((buf[i] | wbuf[offset - addr + i]) != buf[i]) {
                break;
            }
        }

        if (i == rlen) {
            offset += rlen;
        } else {
            //offset = sdfile_erase_sector(offset + i) + erase_size;
            return SDFILE_WRITE_AREA_NEED_ERASE_ERR;
        }

    } while (offset < end_addr);

    return 0;
#else
    const u8 *r_buf = (u8 *)sdfile_flash_addr2cpu_addr(addr);
    for (int i = 0; i < len; i++) {
        if ((wbuf[i] & r_buf[i]) != wbuf[i]) {
            return SDFILE_WRITE_AREA_NEED_ERASE_ERR;
        }
    }
    return 0;
#endif
}


#if (VFS_ENABLE == 1)

static int sdfile_open(FILE *_file, const char *path, const char *mode)
{
    int ret = 0;
    const char *path_new = path;
    struct sdfile_dir dir;
    char name[16 + 1] = {0};

    if (path == NULL) {
        return SDFILE_FILE_NOT_EXIST;
    }

    SDFILE *pfile = (SDFILE *)malloc(sizeof(SDFILE));

    if (!pfile) {
        return 0;
    }
    memset(pfile, 0, sizeof(SDFILE));

    if (!strcmp(_file->part->dir, "app")) {
        ret = sdfile_open_app_file(pfile, path_new);
    } else if (!strcmp(_file->part->dir, "res")) {
        ret = sdfile_open_res_file(pfile, path_new);
    } else if (!strcmp(_file->part->dir, "EXT_RESERVED")) {
        ret = sdfile_open_ext_res_file(pfile, path_new);
    } else {
        log_error("sdfile not support part %s", name);
        goto _err_exit;
    }
    if (ret == SDFILE_SUSS) {
        //log_info("Open [%s] Succ (^_^)", path);
        _file->private_data = pfile;
        return 0;
    }

_err_exit:
    log_debug("Open 0x%x, [%s] Fail! (>_<)", path, path);
    free(pfile);
    return ret;
}

static int sdfile_read(FILE *_file, void *buf, u32 len)
{
    u32 remain_len;
    u32 rlen;

    if (_file == NULL) {
        return 0;
    }

    SDFILE *pfile = (SDFILE *)_file->private_data;

    if (pfile == NULL) {
        return 0;
    }

    remain_len = pfile->head.len - pfile->fptr;
    rlen = len;

    if (remain_len < len) {
        rlen = remain_len;
    }

    memcpy((u8 *)buf, (u8 *)(pfile->fptr + pfile->head.addr), len);

    pfile->fptr += rlen;

    return rlen;
}

static int sdfile_seek(FILE *_file, int offset, int fromwhere)
{
    if (_file == NULL) {
        return 0;
    }

    SDFILE *pfile = (SDFILE *)_file->private_data;

    if (pfile == NULL) {
        return 0;
    }

    switch (fromwhere) {
    case SEEK_SET:
        pfile->fptr = offset;
        break;
    case SEEK_CUR:
        pfile->fptr += offset;
        break;
    case SEEK_END:
        pfile->fptr = pfile->head.len - offset;
        break;
    }

    return 0;
}



static int sdfile_write(FILE *_file, void *buf, u32 len)
{
    u32 remain_len;
    u32 wlen;
    u32 waddr;
    int ret;

    if (_file == NULL) {
        return 0;
    }

    SDFILE *pfile = (SDFILE *)_file->private_data;

    if (pfile == NULL) {
        return 0;
    }

    remain_len = pfile->head.len - pfile->fptr;
    wlen = len;

    if (remain_len < len) {
        wlen = remain_len;
    }

    waddr = pfile->fptr + pfile->head.addr; 			//cpu logic addr
    waddr = sdfile_cpu_addr2flash_addr(waddr);  	//flash addr

    ret = sdfile_write_area_check(buf, waddr, wlen);  //flash addr
    if (ret) {
        return ret;  //由上层负责擦除
    }

    ret = norflash_write(NULL, (u8 *)buf, wlen, waddr);

    if (ret == wlen) {
        pfile->fptr += wlen;
    }

    return ret;
}

static int sdfile_close(FILE *_file)
{
    if (_file == NULL) {
        return 0;
    }

    SDFILE *pfile = (SDFILE *)_file->private_data;

    if (pfile) {
        free(pfile);
    }

    return 0;
}

static int sdfile_len(FILE *_file)
{
    if (_file == NULL) {
        return 0;
    }

    SDFILE *pfile = (SDFILE *)_file->private_data;

    if (pfile == NULL) {
        return 0;
    }

    return pfile->head.len;
}

static int sdfile_pos(FILE *_file)
{
    if (_file == NULL) {
        return 0;
    }

    SDFILE *pfile = (SDFILE *)_file->private_data;

    if (pfile) {
        return pfile->fptr;
    }

    return 0;
}

static int sdfile_get_name(FILE *_file, u8 *name, int len)
{
    if (_file == NULL) {
        return 0;
    }

    SDFILE *pfile = (SDFILE *)_file->private_data;

    if (!pfile) {
        return 0;
    }

    if (len > 16) {
        len = 16;
    }
    memcpy(name, pfile->head.name, len);

    return len;
}

static int sdfile_get_attrs(FILE *_file, struct vfs_attr *attr)
{
    if (_file == NULL) {
        return 0;
    }

    SDFILE *pfile = (SDFILE *)_file->private_data;

    if (!pfile) {
        return 0;
    }

    /* attr->attr = pfile->head.attr; */
    if ((pfile->head.attr & SDFILE_FILE_ATTR_TYPE_MASK) == SDFILE_FILE_ATTR_DIR) {
        attr->attr |= F_ATTR_DIR;
    } else if ((pfile->head.attr & SDFILE_FILE_ATTR_TYPE_MASK) == SDFILE_FILE_ATTR_REG) {
        /* attr->attr |= F_ATTR_RO; */
    }

    attr->fsize = pfile->head.len;
    attr->sclust = pfile->head.addr;
    return 0;
}


static int sdfile_mount(struct imount *mt, int cache_num)
{
    struct vfs_partition *app_part = &mt->part;
    struct vfs_partition *res_part = NULL;

    if (sdfile->ext_res_part_addr) {
        struct vfs_partition *ext_res_part = vfs_partition_next(app_part);
        res_part = vfs_partition_next(ext_res_part);
        ext_res_part->offset = sdfile->ext_res_part_addr;
        memcpy(ext_res_part->dir, "EXT_RESERVED", VFS_PART_DIR_MAX);
        ext_res_part->dir[strlen(ext_res_part->dir)] = '\0';
        mt->part_num = 3;
    } else {
        res_part = vfs_partition_next(app_part);
        mt->part_num = 2;
    }

    app_part->offset = sdfile->app_part_addr;
    app_part->dir[0] = 'a';
    app_part->dir[1] = 'p';
    app_part->dir[2] = 'p';

    app_part->dir[3] = '\0';

    res_part->offset = sdfile->res_part_addr;
    res_part->dir[0] = 'r';
    res_part->dir[1] = 'e';
    res_part->dir[2] = 's';
    res_part->dir[3] = '\0';


    return 0;
}

#if NOR_SDFILE_ENABLE
int res_saddr = 0; //用于外挂flash放置提示音 或资源文件的偏移地址。
int set_res_startaddr(int offset)
{
    res_saddr = offset;
    return res_saddr;
}

int sdfile_get_addr(void)
{
    return nor_sdfile_hdl.addr_offset;
}

static OS_MUTEX nor_sdfile_mutex;

static void *sdfile_fd;
/* static int hook_norsdfile_open(void) */
/* { */
/*     sdfile_fd = dev_open("norfs", NULL); */
/*     if (sdfile_fd == NULL) { */
/*         log_e("error!!!!!!,fd == NULL"); */
/*         return false; */
/*     } */
/*     return true; */
/* } */
static int hook_norsdfile_spirec_read(u8 *buf, u32 addr, u32 len)
{
    return dev_bulk_read(sdfile_fd, buf, addr, len);
}
u32 init_norsdfile_hdl(void)
{
    os_mutex_create(&nor_sdfile_mutex);
    nor_sdfile_hdl.read = hook_norsdfile_spirec_read;
    return true;
}

int hook_norsdfile_read(u8 *buf, u32 addr, u32 len)
{
    os_mutex_pend(&nor_sdfile_mutex, 0);
    nor_sdfile_hdl.read(buf, addr, len);
    os_mutex_post(&nor_sdfile_mutex);
    return true;
}

static int nor_sdfile_for_each_file_in_dir(u32 org_addr, struct sdfile_file_head *ret_head, char *dest_name)
{
    u32 addr = 0;
    int err_cnt = 32;
    int ret = 0;
    struct sdfile_file_head head;

    for (addr = org_addr; err_cnt > 0; addr += sizeof(struct sdfile_file_head)) {
        /* memcpy((u8 *)&head, (u8 *)addr, sizeof(struct sdfile_file_head)); */
        hook_norsdfile_read((u8 *)&head, addr, sizeof(struct sdfile_file_head));


        if (CRC16((u8 *)&head + 2, sizeof(struct sdfile_file_head) - 2) != head.head_crc) {
            err_cnt--;
            continue;
        }
        ret = sdfile_strcase_cmp(head.name, dest_name);

        if (!ret) {
            if (ret_head) {
                memcpy((u8 *)ret_head, (u8 *)&head, sizeof(struct sdfile_file_head));
            }
            return SDFILE_SUSS;
        }

        if (head.index) {
            return SDFILE_END;
        }
    }

    return SDFILE_FILE_NOT_EXIST;
}

static int nor_sdfile_for_each_dir(struct sdfile_file_head *dir_head, const char *dest_name)
{
    int ret;
    struct sdfile_file_head head;
    u32 addr = sdfile->dir_addr;
    addr += res_saddr;

    do {
        hook_norsdfile_read((u8 *)&head, addr, sizeof(struct sdfile_file_head));
        /* memcpy((u8 *)&head, (u8 *)addr, sizeof(struct sdfile_file_head)); */
        if (CRC16((u8 *)&head + 2, sizeof(struct sdfile_file_head) - 2) != head.head_crc) {
            return SDFILE_DATA_CRC_ERR;
        }

        ret = sdfile_strcase_cmp(head.name, dest_name);
        if (!ret) {
            memcpy((u8 *)dir_head, (u8 *)&head, sizeof(struct sdfile_file_head));
            dir_head->addr = addr;
            return SDFILE_SUSS;
        }

        addr += head.len;
    } while (head.index == 0);

    return SDFILE_DIR_NOT_EXIST;
}

static int nor_sdfile_open_dir(struct sdfile_dir *dir, const char *dest_name)
{
    int ret;
    ret = nor_sdfile_for_each_dir(&(dir->head), dest_name);
    if (ret == SDFILE_SUSS) {
        if ((dir->head.attr & SDFILE_FILE_ATTR_TYPE_MASK) == SDFILE_FILE_ATTR_DIR) {
            ret = SDFILE_SUSS;
        } else {
            ret = SDFILE_DIR_NOT_EXIST;
        }
    }

    return ret;
}

static int nor_sdfile_open_file_in_dir(struct sdfile_file_t *file, struct sdfile_dir *dir, char *name)
{
    int ret;

    u32 org_addr = dir->head.addr + sizeof(struct sdfile_file_head);
    file->fptr = 0;

    ret = nor_sdfile_for_each_file_in_dir(org_addr, &file->head, name);

    if (ret == SDFILE_SUSS) {
        if ((file->head.attr & SDFILE_FILE_ATTR_RESERVED) == SDFILE_FILE_ATTR_RESERVED) {
            //printf("res abs addr @ 0x%x", file->head.addr);
            // reserved file, absolute addr
            file->head.addr = sdfile_flash_addr2cpu_addr(file->head.addr);
        } else {
            file->head.addr += dir->head.addr;
            //printf("normal file @ 0x%x", file->head.addr);
        }
    }

    return ret;
}

static int nor_sdfile_open_file_in_root(struct sdfile_file_t *file, const char *dest_name)
{
    int ret;
    file->fptr = 0;

    ret = nor_sdfile_for_each_dir(&(file->head), dest_name);

    if (ret == SDFILE_SUSS) {
        file->head.addr += sizeof(struct sdfile_file_head);
        file->head.len -= sizeof(struct sdfile_file_head);
    }

    return ret;
}

static int nor_sdfile_open(FILE *_file, const char *path, const char *mode)
{
    int ret;
    const char *path_new = path;
    struct sdfile_dir dir;
    char name[16 + 1];

    if (path == NULL) {
        return SDFILE_FILE_NOT_EXIST;
    }

    struct sdfile_file_t *pfile = malloc(sizeof(struct sdfile_file_t));
    if (!pfile) {
        return -ENOMEM;
    }
    memset(pfile, 0, sizeof(struct sdfile_file_t));

    if (!strcmp(_file->part->dir, "C")) {
        path_new = __sdfile_path_get_name(path_new, name);

        if (*path_new) {
            // dir
            ret = nor_sdfile_open_dir(&dir, name);
            if (ret) {
                goto _err_exit;
            }
            path_new = __sdfile_path_get_name(path_new, name);

            ret = nor_sdfile_open_file_in_dir(pfile, &dir, name);
        } else {
            // file
            ret = nor_sdfile_open_file_in_root(pfile, name);
        }

    } else {
        ret = -ENODEV;
        goto _err_exit;
    }

    if (ret == 0) {
        log_info("Open [%s] Succ (^_^)", path);
        _file->private_data = pfile;
        return 0;
    }

_err_exit:
    log_debug("Open 0x%x, [%s] Fail! (>_<)", path, path);
    free(pfile);
    return ret;
}

static int nor_sdfile_read(FILE *_file, void *buf, u32 len)
{
    u32 remain_len;
    u32 rlen;

    if (_file == NULL) {
        return 0;
    }

    SDFILE *pfile = (SDFILE *)_file->private_data;

    if (pfile == NULL) {
        return 0;
    }

    remain_len = pfile->head.len - pfile->fptr;
    rlen = len;

    if (remain_len < len) {
        rlen = remain_len;
    }

    /* memcpy((u8 *)buf, (u8 *)(pfile->fptr + pfile->head.addr), len); */
    hook_norsdfile_read((u8 *)buf, (pfile->fptr + pfile->head.addr), len);


    pfile->fptr += rlen;

    return rlen;
}

static int nor_sdfile_mount(struct imount *mt, int cache_num)
{
    struct vfs_partition *app_part = &mt->part;
    sdfile_fd = mt->dev.fd;
    /* hook_norsdfile_open(); */
    app_part->offset = res_saddr ;
    app_part->dir[0] = 'C';
    app_part->dir[1] = '\0';

    mt->part_num = 1;
    return 0;

}
#endif


#if SDFILE_STORAGE

#ifndef AM_DIR
#define AM_DIR	0x10	/* Directory */
#endif /* #ifndef AM_DIR */

static bool _sdf_type_compare(const char *types, const char *ext)
{
    const char *str;
    char str_tmp[3];
    char ext_tmp[3];
    memcpy(ext_tmp, ext, 3);
    sdfile_str_to_upper(ext_tmp, 3);

    if (!types || !ext) {
        return false;
    }

    for (str = types; *str != '\0'; str += 3) {
        memcpy(str_tmp, str, 3);
        sdfile_str_to_upper(str_tmp, 3);
        if (0 == ASCII_StrCmp(ext_tmp, str_tmp, 3)) {
            return true;
        }
    }

    return false;
}
static bool _sdf_loadFileInfo(struct sdfile_scn *scan, SDFILE *pFile)
{
    pFile->fptr = 0;
    memcpy((u8 *)&pFile->head, (u8 *)&scan->head, sizeof(struct sdfile_file_head));
    return true;
}

static void _sdf_scan_dir_init(struct sdfile_scn *scan)
{
    scan->deepth = 0;
    scan->folder[scan->deepth].saddr = sdfile->res_part_addr;
}

static void _sdf_opendir(struct sdfile_folder *folder)
{
    folder->addr = folder->saddr;
    folder->len = 0;
}
static int _sdf_readnextdir(struct sdfile_folder *folder, struct sdfile_file_head *phead)
{
    folder->addr += folder->len;
    memcpy((u8 *)phead, (u8 *)folder->addr, sizeof(struct sdfile_file_head));
    /* printf("\naddr:0x%x ", folder->addr); */
    /* printf_buf(phead, sizeof(struct sdfile_file_head)); */
    if (CRC16((u8 *)phead + 2, sizeof(struct sdfile_file_head) - 2) != phead->head_crc) {
        return SDFILE_DATA_CRC_ERR;
    }
    /* log_i("file attr:0x%x, name:%s, ", phead->attr, phead->name); */
    if (folder->saddr <= sdfile->res_part_addr) { // root
        folder->len = phead->len;
        phead->addr = folder->addr + sizeof(struct sdfile_file_head);
        phead->len -= sizeof(struct sdfile_file_head);
    } else {
        folder->len = sizeof(struct sdfile_file_head);
        phead->addr = folder->saddr + phead->addr - sizeof(struct sdfile_file_head);
    }
    return 0;
}

static int _sdf_opendir_by_name(struct sdfile_folder *folder, const char *path)
{
    int ret;
    struct sdfile_file_head head;
    char name[16 + 1] = {0};
    const char *path_new = path;
    path_new = __sdfile_path_get_name(path_new, name);

    _sdf_opendir(folder);

    while (*path_new || (name[0] != 0)) {
        do {
            ret = _sdf_readnextdir(folder, &head);
            if (ret) {
                goto __exit;
            }

            if ((head.attr & SDFILE_FILE_ATTR_TYPE_MASK) == SDFILE_FILE_ATTR_DIR) {
                ret = sdfile_strcase_cmp(head.name, name);
                if (!ret) {
                    folder->saddr = head.addr;
                    _sdf_opendir(folder);
                    break;
                }
            }
        } while (head.index == 0);
        memset(name, 0, sizeof(name));
        path_new = __sdfile_path_get_name(path_new, name);
    }

__exit:
    if (*path_new) {
        return SDFILE_DIR_NOT_EXIST;
    }
    return SDFILE_SUSS;
}

static int _sdf_scan_dir(struct sdfile_scn *scan, bool subpath,
                         const char *ftypes, int attr,
                         int (*callback)(void *, struct sdfile_file_head *), void *priv)
{
    int ret;
    struct sdfile_file_head head;

_SEARCH_FILE:
    do {
        ret = _sdf_readnextdir(&scan->folder[scan->deepth], &head);
        if (ret) {
            break;
        }
        if ((head.attr & SDFILE_FILE_ATTR_TYPE_MASK) == SDFILE_FILE_ATTR_DIR) {
            if (!(attr & AM_DIR)) {
                continue;
            }
            ret = callback(priv, &head);
            if (ret) {
                return ret;
            }
        } else if ((head.attr & SDFILE_FILE_ATTR_TYPE_MASK) == SDFILE_FILE_ATTR_REG) {
            /* if (!(dir_info.obj.attrib & attr)) { */
            /* continue; */
            /* } */
            /* if (!(attr & AM_RDO) && (dir_info.obj.attrib & AM_RDO)) { */
            /* continue; */
            /* } */
            char *ext = strrchr(head.name, '.');
            if (!ext) {
                continue;
            }
            ext++;
            if (_sdf_type_compare(ftypes, ext)) {
                ret = callback(priv, &head);
                if (ret) {
                    return ret;
                }
            }
        }
    } while (head.index == 0);

    if (!subpath) {			//只搜索当前目录的文件数目
        return 0;
    }

    _sdf_opendir(&scan->folder[scan->deepth]);

    if (scan->deepth < (SDFILE_MAX_DEEPTH - 1)) {
_SEARCH_DIR:
        do {
            ret = _sdf_readnextdir(&scan->folder[scan->deepth], &head);
            if (ret) {
                break;
            }
            if ((head.attr & SDFILE_FILE_ATTR_TYPE_MASK) == SDFILE_FILE_ATTR_DIR) {
                scan->fileTotalInDir = 0;
                scan->fileTotalOutDir = scan->fileCounter;
                scan->deepth++;
                scan->folder[scan->deepth].saddr = head.addr;
                _sdf_opendir(&scan->folder[scan->deepth]);
                goto _SEARCH_FILE;
            }
        } while (head.index == 0);
    }

    if (scan->deepth) {
        scan->deepth--;
        goto _SEARCH_DIR;               //接上次搜索，不能重新打开dir
    }
    return 0;
}

static int _sdf_seach_total(void *priv, struct sdfile_file_head *phead)
{
    struct sdfile_scn *scan = (struct sdfile_scn *)priv;

    scan->fileCounter++;

    return 0;
}

static int _sdf_getfile_totalindir(struct sdfile_scn *scan)
{
    int res;
    struct sdfile_scn scan_tmp;
    memcpy(&scan_tmp, scan, sizeof(struct sdfile_scn));

    scan_tmp.fileCounter = 0;
    _sdf_opendir(&scan_tmp.folder[scan_tmp.deepth]);
    res = _sdf_scan_dir(&scan_tmp, 0, scan_tmp.ftypes, scan_tmp.attr, _sdf_seach_total, &scan_tmp);
    if (res) {
        return 0;
    }
    return scan_tmp.fileCounter;
}

static int _sdf_seach_file_by_number(void *priv, struct sdfile_file_head *phead)
{
    struct sdfile_scn *scan = (struct sdfile_scn *)priv;

    if (++scan->fileCounter == scan->fileNumber) {
        memcpy(&scan->head, phead, sizeof(struct sdfile_file_head));
        return 1;
    }

    return 0;
}

static int _sdf_open_file_by_number(SDFILE *file, struct sdfile_scn *scan, int fileNumber)
{
    int res;

    /* log_i("open_file_bynumber:%d \n", fileNumber); */

    if (fileNumber == scan->fileNumber) {      //当前文件与打开的文件相同
        if (true == _sdf_loadFileInfo(scan, file)) {
            /*log_i("open_suss_1\n");*/
            return 0;
        }
        return SDFILE_FILE_NOT_EXIST;
    }

    if ((fileNumber > scan->fileNumber) && (scan->fileNumber != 0)) {
        //新文件序号比当前文件大，可以接上次的搜索
        scan->fileCounter = scan->fileNumber;
    } else {
        //需重新搜索
        scan->deepth = 0;
        scan->fileCounter = 0;
        scan->fileTotalInDir = 0;
        scan->fileTotalOutDir = 0;
        _sdf_opendir(&scan->folder[scan->deepth]);
    }

    scan->fileNumber = fileNumber;			//新的文件序号
    res = _sdf_scan_dir(scan, scan->subpath, scan->ftypes, scan->attr, _sdf_seach_file_by_number, scan);
    if (res == 1) {
        if (true == _sdf_loadFileInfo(scan, file)) {
            scan->fileNumber = scan->fileCounter;
            if (scan->fileTotalInDir == 0) {
                scan->fileTotalInDir = _sdf_getfile_totalindir(scan);
            }
            return 0;
        }
    }

    return SDFILE_FILE_NOT_EXIST;
}

static int _sdf_seach_file_by_clust(void *priv, struct sdfile_file_head *phead)
{
    struct sdfile_scn *scan = (struct sdfile_scn *)priv;

    scan->fileCounter++;

    if (phead->addr == scan->sclust_id) {
        memcpy(&scan->head, phead, sizeof(struct sdfile_file_head));
        return 1;
    }

    return 0;
}

static int _sdf_open_file_by_clust(SDFILE *file, struct sdfile_scn *scan, int clust)
{
    int res;

    scan->deepth = 0;
    scan->fileNumber = 0;
    scan->fileCounter = 0;
    scan->sclust_id = clust;
    scan->fileTotalInDir = 0;
    scan->fileTotalOutDir = 0;
    _sdf_opendir(&scan->folder[scan->deepth]);

    res = _sdf_scan_dir(scan, scan->subpath, scan->ftypes, scan->attr, _sdf_seach_file_by_clust, scan);
    if (res == 1) {
        if (true == _sdf_loadFileInfo(scan, file)) {
            scan->fileNumber = scan->fileCounter;
            if (scan->fileTotalInDir == 0) {
                scan->fileTotalInDir = _sdf_getfile_totalindir(scan);
            }
            return 0;
        }
    }

    return SDFILE_FILE_NOT_EXIST;
}

static int _sdf_store_number(void *priv, struct sdfile_file_head *phead)
{
    struct sdfile_scn *scan = (struct sdfile_scn *)priv;

    scan->fileCounter++;

    return 0;
}

static int _sdf_scan(struct sdfile_scn *scan, const char *path, bool subpath, const char *ftypes, u8 attr)
{
    int i;
    int err;

    scan->subpath = subpath;
    scan->ftypes = ftypes;
    scan->attr = attr;

    _sdf_scan_dir_init(scan);
    err = _sdf_opendir_by_name(&scan->folder[0], path);
    if (err) {
        goto __err;
    }

    err = _sdf_scan_dir(scan, scan->subpath, scan->ftypes, scan->attr, _sdf_store_number, scan);
    if (err) {
        goto __err;
    }

    scan->totalFileNumber = scan->fileCounter;
    scan->last_file_number = scan->totalFileNumber;

    if (scan->fileTotalInDir == 0) {
        /* scan->fileTotalInDir = _sdf_getfile_totalindir(scan);	 */
    }

    /* log_i("total:%d, last:%d \n", scan->totalFileNumber, scan->last_file_number); */

    return 0;

__err:
    return SDFILE_FILE_NOT_EXIST;
}

static int _sdf_select_file(struct sdfile_scn *scan, int sel_mode, SDFILE *file, int arg)
{
    int err;
    int fnum = 0;

    if (scan->totalFileNumber == 0) {
        return -ENOENT;
    }

    int file_start = 1;
    int file_end = scan->totalFileNumber;

    if ((scan->cycle_mode == FCYCLE_FOLDER) && (scan->fileTotalInDir)
        && ((scan->fileTotalOutDir + scan->fileTotalInDir) <= scan->totalFileNumber)
       ) {
        file_start = scan->fileTotalOutDir + 1;
        file_end = scan->fileTotalOutDir + scan->fileTotalInDir;
    }

    switch (sel_mode) {
    case FSEL_LAST_FILE:
        scan->fileNumber = 0;
        fnum = scan->totalFileNumber;
        scan->last_file_number = fnum;
        break;
    case FSEL_FIRST_FILE:
        fnum = 1;
        scan->fileNumber = 0;
        scan->last_file_number = scan->totalFileNumber;
        break;
    case FSEL_AUTO_FILE:
        if (scan->fileNumber == 0) {
            return -EINVAL;
        }
        if (scan->cycle_mode == FCYCLE_ONE) {
            fnum = scan->fileNumber;
            break;
        }
    case FSEL_NEXT_FILE:
        if (scan->fileNumber == 0) {
            return -EINVAL;
        }
        if (scan->cycle_mode == FCYCLE_RANDOM) {
            fnum = rand32() % (file_end - file_start + 1) + file_start;
            if (fnum == scan->fileNumber) {
                fnum = scan->fileNumber + 1;
            }
        } else {
            fnum = scan->fileNumber + 1;
        }
        if (fnum > scan->last_file_number) {
            if (scan->cycle_mode == FCYCLE_LIST) {
                return -ENOENT;
            }
            fnum = 1;
        }
        if (fnum > file_end) {
            fnum = file_start;
        } else if (fnum < file_start) {
            fnum = file_end;
        }
        break;
    case FSEL_PREV_FILE:
        if (scan->fileNumber == 0) {
            return -EINVAL;
        }
        if (scan->cycle_mode == FCYCLE_RANDOM) {
            fnum = rand32() % (file_end - file_start + 1) + file_start;
            if (fnum == scan->fileNumber) {
                fnum = scan->fileNumber + 1;
            }
        } else {
            fnum = scan->fileNumber - 1;
        }
        scan->last_file_number = scan->totalFileNumber;
        if (scan->cycle_mode == FCYCLE_LIST) {
            break;
        }
        if (fnum > file_end) {
            fnum = file_start;
        } else if (fnum < file_start) {
            fnum = file_end;
        }
        break;
    case FSEL_BY_NUMBER:
        fnum = arg;
        break;
    case FSEL_BY_SCLUST:
        if (_sdf_open_file_by_clust(file, scan, arg)) {
            return -EINVAL;
        }
        fnum = scan->fileNumber;
        break;
    default:
        return -EINVAL;
    }

    if (fnum == 0) {
        return -ENOENT;
    }

    if (fnum < file_start) {
        fnum = file_start;
    } else if (fnum > file_end) {
        fnum = file_end;
    }

    if (sel_mode != FSEL_BY_SCLUST) {
        err = _sdf_open_file_by_number(file, scan, fnum);
        if (err) {
            /*log_i("---open_file_bynumber: err\n");*/
            return err;
        }
    }

    return 0;
}

static int sdfile_scan(struct vfscan *fscan, const char *path, u8 max_deepth)
{
    SDFILE_VFS_REDUCE_BEGIN();
    u8 attr = 0;

    if ((!fscan->sort) || (fscan->sort == '\0') || (fscan->sort == 'n')) {
        // scan by number
    } else {
        log_e("\n fscan : %s \n", fscan->sort);
        return -EINVAL;
    }
    if (strcmp(fscan->part->dir, "res")) {
        return -EINVAL;
    }

    if (fscan->attr & F_ATTR_RO) {
        /* attr |= AM_RDO; */
    }
    if (fscan->attr & F_ATTR_ARC) {
        /* attr |= AM_ARC; */
    }
    if (fscan->attr & F_ATTR_DIR) {
        attr |= AM_DIR;
    }

    struct sdfile_scn *scan_hdl = zalloc(sizeof(struct sdfile_scn));
    if (!scan_hdl) {
        log_e("scn hdl create err \n");
        return -ENOMEM;
    }

    int err = _sdf_scan(scan_hdl, path, fscan->subpath, fscan->ftype, attr);
    if (err) {
        log_e("scn err:%d \n", err);
        free(scan_hdl);
        return -EFAULT;
    }

    fscan->priv = scan_hdl;
    fscan->file_number = scan_hdl->totalFileNumber;

    return 0;
    SDFILE_VFS_REDUCE_END();
}

static void sdfile_scan_release(struct vfscan *fscan)
{
    SDFILE_VFS_REDUCE_BEGIN();
    if (fscan->priv) {
        free(fscan->priv);
        fscan->priv = NULL;
    }
    SDFILE_VFS_REDUCE_END_V2();
}

static int sdfile_sel(struct vfscan *fscan, int sel_mode, FILE *file, int arg)
{
    SDFILE_VFS_REDUCE_BEGIN();
    int err;
    struct sdfile_scn *scan_hdl = (struct sdfile_scn *)fscan->priv;
    SDFILE *fh = (SDFILE *)zalloc(sizeof(SDFILE));
    if (!fh) {
        return -ENOMEM;
    }

    scan_hdl->cycle_mode = fscan->cycle_mode;
    err = _sdf_select_file(scan_hdl, sel_mode, fh, arg);
    if (err) {
        free(fh);
        return err;
    }
    fscan->file_counter = scan_hdl->fileNumber;
    /* fh->private_data = scan_hdl; */

    file->private_data = fh;

    return 0;
    SDFILE_VFS_REDUCE_END();
}

///-------------------------以下函数为目录浏览使用-------------------------------///
static u32 sdfile_open_dir_info(SDFILE *f_p, char *ftypes, void *dir_dj)
{
    int ret;
    struct sdfile_file_head head;
    struct sdfile_folder *folder;
    struct sdfile_scn *scan = f_p->pscn;
    FS_DIR_INFO *arg_dir_info = dir_dj;

    /* printf("deep:%d, ftypes:%s, ", scan->deepth, ftypes); */

    if (arg_dir_info) {
        folder = &scan->folder[scan->deepth];
        if (arg_dir_info->dir_type) { //it's file,open file
//            puts("打开指定文件\n");
            return 0;
        } else { //it's dir,enter fir
            if ((scan->deepth < (SDFILE_MAX_DEEPTH - 1)) && (arg_dir_info->sclust)) {
//                puts("从指定目录开始扫描\n");
                scan->deepth++;
                scan->fileTotalInDir = 0;
                folder++;
                folder->saddr = arg_dir_info->sclust;
            } else if (scan->deepth == 0) {
//                puts("从根目录开始扫描\n");
                memset(folder, 0, sizeof(struct sdfile_folder)*SDFILE_MAX_DEEPTH);
                _sdf_scan_dir_init(scan);
            }
        }
    } else {
        scan->deepth = 0;
        folder = &scan->folder[scan->deepth];
        memset(folder, 0x00, sizeof(struct sdfile_folder));
        _sdf_scan_dir_init(scan);
    }

    scan->dirCounter = 0;
    scan->fileCounter = 0;
    scan->fileNumber = 0;

    _sdf_opendir(folder);             //重新进入目录开始扫描

    do {
        ret = _sdf_readnextdir(folder, &head);
        if (ret) {
            break;
        }
        if ((head.attr & SDFILE_FILE_ATTR_TYPE_MASK) == SDFILE_FILE_ATTR_DIR) {
            /* printf("dirname:%s ", head.name); */
            scan->dirCounter++;
        } else if ((head.attr & SDFILE_FILE_ATTR_TYPE_MASK) == SDFILE_FILE_ATTR_REG) {
            /* printf("filename:%s ", head.name); */
            char *ext = strrchr(head.name, '.');
            if (!ext) {
                continue;
            }
            ext++;
            if (_sdf_type_compare(ftypes, ext)) {
                scan->fileCounter++;
            }
        }
    } while (head.index == 0);

    scan->fileTotalInDir = scan->fileCounter + scan->dirCounter;//fileTotalInDir:目录浏览时，用于计数文件夹和文件总数
//    printf("res = %x\n",res);
    /* printf("file_total = %d\n",scan->fileTotalInDir); */

    return scan->fileTotalInDir;
}

static u32 sdfile_exit_dir_info(SDFILE *f_p, char *ftypes)
{
    int ret;
    struct sdfile_file_head head;
    struct sdfile_folder *folder;
    struct sdfile_scn *scan = f_p->pscn;

    if (scan->deepth > 0) {
        scan->deepth--;
    } else {
        return 0;
    }

    folder = &scan->folder[scan->deepth];

    scan->dirCounter = 0;
    scan->fileCounter = 0;
    scan->fileNumber = 0;

    _sdf_opendir(folder);             //重新进入目录开始扫描

    do {
        ret = _sdf_readnextdir(folder, &head);
        if (ret) {
            break;
        }
        if ((head.attr & SDFILE_FILE_ATTR_TYPE_MASK) == SDFILE_FILE_ATTR_DIR) {
            scan->dirCounter++;
        } else if ((head.attr & SDFILE_FILE_ATTR_TYPE_MASK) == SDFILE_FILE_ATTR_REG) {
            char *ext = strrchr(head.name, '.');
            if (!ext) {
                continue;
            }
            ext++;
            if (_sdf_type_compare(ftypes, ext)) {
                scan->fileCounter++;
            }
        }
    } while (head.index == 0);

    scan->fileTotalInDir = scan->fileCounter + scan->dirCounter;//fileTotalInDir:目录浏览时，用于计数文件夹和文件总数
//    printf("res = %x\n",res);
//    printf("file_total = %d\n",scan->fileTotalInDir);

    return scan->fileTotalInDir;
}

/*----------------------------------------------------------------------------*/
/** @brief:获取同一层目录里面的目录项信息，不进行文件夹进入操作
@param: f_p为虚拟文件句柄
@return: 是否找到指定的文件
@author: GW
@note:
@date: 2015-06-08,14:54
*/
/*----------------------------------------------------------------------------*/
static u32 sdfile_get_dir_info(SDFILE *f_p, char *ftypes, u32 start_num, u32 total_num, void *buf_info)
{
    int ret;
    u32 current_cnt = 0;//文件和文件夹总数
    u32 buf_cnt = 0;
    struct sdfile_file_head head;
    struct sdfile_folder *folder;
    struct sdfile_scn *scan = f_p->pscn;
    FS_DIR_INFO *arg_dir_info = buf_info;

    folder = &scan->folder[scan->deepth];

//    printf("scan->deepth = %d\n",scan->deepth);
//    printf("start_num  %d    total_num = %d\n",start_num,total_num);

    if (scan->fileNumber) {
//        puts("---search-1----\n");
        if (start_num > scan->dirCounter) { //直接搜索文件
//            puts("---search-2----\n");
            if ((start_num <= scan->fileNumber)      //往回搜索，重置目录项
                || (scan->fileNumber <= scan->dirCounter)) {
//                puts("---search-3----\n");
                _sdf_opendir(folder);
                current_cnt = scan->dirCounter;
            } else { //继续搜索
//                puts("---search-4----\n");
                current_cnt = scan->fileNumber;
            }
            goto __search_file;
        } else { //先搜索文件夹
//            puts("---search-5----\n");
            if (start_num <= scan->fileNumber) { //重置目录项
//                puts("---search-6----\n");
                _sdf_opendir(folder);
                current_cnt = 0;
            } else { //继续搜索
//               puts("---search-8----\n");
                current_cnt = scan->fileNumber;
            }
        }
    } else {
//        puts("---search-8----\n");
        _sdf_opendir(folder);
        current_cnt = 0;//scan->dirCounter;
    }

    do {
        ret = _sdf_readnextdir(folder, &head);
        if (ret) {
            break;
        }
        if ((head.attr & SDFILE_FILE_ATTR_TYPE_MASK) == SDFILE_FILE_ATTR_DIR) {
            current_cnt++;
            if (current_cnt >= start_num) {
                //printf("folder = %s\n",head.name);
                arg_dir_info[buf_cnt].fn_type = 0;//it's a sfn
                memcpy(arg_dir_info[buf_cnt].lfn_buf.lfn, head.name, SDFILE_NAME_LEN);
                arg_dir_info[buf_cnt].sclust = head.addr;
                arg_dir_info[buf_cnt].dir_type = 0;
                buf_cnt++;
                if (buf_cnt >= total_num) {
                    goto __cnt_return;
                }
            }
        }
    } while (head.index == 0);

    scan->fileNumber = current_cnt;// folder cnt
    _sdf_opendir(folder);

__search_file:
//    printf("current_cnt = %d\n",current_cnt);
    do {
        ret = _sdf_readnextdir(folder, &head);
        if (ret) {
            break;
        }
        if ((head.attr & SDFILE_FILE_ATTR_TYPE_MASK) == SDFILE_FILE_ATTR_REG) {
            char *ext = strrchr(head.name, '.');
            if (!ext) {
                continue;
            }
            ext++;
            if (_sdf_type_compare(ftypes, ext)) {
                current_cnt++;
                if (current_cnt >= start_num) {
                    //printf("file = %s\n",head.name);
                    arg_dir_info[buf_cnt].fn_type = 0;//it's a sfn
                    memcpy(arg_dir_info[buf_cnt].lfn_buf.lfn, head.name, SDFILE_NAME_LEN);
                    arg_dir_info[buf_cnt].sclust = head.addr;
                    arg_dir_info[buf_cnt].dir_type = 1;
                    buf_cnt++;
                    if (buf_cnt >= total_num) {
                        goto __cnt_return;
                    }
                }
            }
        }
    } while (head.index == 0);

__cnt_return:

    scan->fileNumber = current_cnt;//fileNumber:目录浏览时，用于计数当前浏览最后的文件或者文件夹号
//    printf("----return number = %d----\n",buf_cnt);

    return buf_cnt;
}

static int sdfile_get_attr(FILE *file, int *attr)
{
    SDFILE_VFS_REDUCE_BEGIN();
    SDFILE *fh = (SDFILE *)file->private_data;

    if ((fh->head.attr & SDFILE_FILE_ATTR_TYPE_MASK) == SDFILE_FILE_ATTR_DIR) {
        *attr |= F_ATTR_DIR;
    } else if ((fh->head.attr & SDFILE_FILE_ATTR_TYPE_MASK) == SDFILE_FILE_ATTR_REG) {
        /* *attr |= F_ATTR_RO; */
    }

    return 0;
    SDFILE_VFS_REDUCE_END();
}

static int sdfile_ioctl(void *priv, int cmd, int arg)
{
    SDFILE_VFS_REDUCE_BEGIN();
    switch (cmd) {
    case FS_IOCTL_GET_FOLDER_INFO: {
        struct vfscan *fscan = (struct vfscan *)priv;
        struct sdfile_scn *result = (struct sdfile_scn *)fscan->priv;
        struct ffolder *folder = (struct ffolder *)arg;
        if (result) {
            folder->fileStart = result->fileTotalOutDir + 1;
            folder->fileTotal = result->fileTotalInDir;
        }
    }
    break;

    case FS_IOCTL_SET_EXT_TYPE: {
        struct vfs_partition *part = (struct vfs_partition *)priv;
        part->private_data = (char *)arg;
    }
    break;
    case FS_IOCTL_OPEN_DIR: {
        FILE *file = (FILE *)priv;
        struct vfs_partition *part = (struct vfs_partition *)file->part;
        SDFILE *fh;

        if (!file->private_data) {
            fh = zalloc(sizeof(SDFILE) + sizeof(struct sdfile_scn));
            if (!fh) {
                return -ENOMEM;
            }
            fh->pscn = (struct sdfile_scn *)((int)fh + sizeof(SDFILE));
            _sdf_scan_dir_init(fh->pscn);
            file->private_data = fh;
        } else {
            fh = file->private_data;
        }
        if (!fh->pscn) {
            return -EPERM;
        }

        int *inparam = (int *)arg;
        void *dir_dj = (void *)inparam[1];
        inparam[0] = sdfile_open_dir_info(fh, part->private_data, dir_dj);
    }
    break;
    case FS_IOCTL_EXIT_DIR: {
        FILE *file = (FILE *)priv;
        struct vfs_partition *part = (struct vfs_partition *)file->part;
        SDFILE *fh = file->private_data;
        if (!fh || !fh->pscn) {
            return -EPERM;
        }
        int *inparam = (int *)arg;
        inparam[0] = sdfile_exit_dir_info(fh, part->private_data);
    }
    break;
    case FS_IOCTL_GET_DIR_INFO: {
        FILE *file = (FILE *)priv;
        struct vfs_partition *part = (struct vfs_partition *)file->part;
        SDFILE *fh = file->private_data;
        if (!fh || !fh->pscn) {
            return -EPERM;
        }
        int *inparam = (int *)arg;
        u32 start_num = inparam[1];
        u32 total_num = inparam[2];
        void *buf_info = (void *)inparam[3];
        inparam[0] = sdfile_get_dir_info(fh, part->private_data, start_num, total_num, buf_info);
    }
    break;

    default:
        return -EPERM;
    }

    return 0;
    SDFILE_VFS_REDUCE_END();
}

#endif

static int sdfile_delete(FILE *file)
{
    u32 addr, len;
    bool ret;

    SDFILE *fp = (SDFILE *)file->private_data;
    if (fp == NULL) {
        return 0;
    }

    addr = fp->head.addr; 			//cpu logic addr
    addr = sdfile_cpu_addr2flash_addr(addr);  	//flash addr
    len = fp->head.len;
    ret =  sfc_erase_zone(addr, len);
    if (ret == false) {
        log_e("erase error!!!!!!!!!!!!");
        return 0;
    }

    return 1;
}

REGISTER_VFS_OPERATIONS(sdfile_vfs_ops) = {
    .fs_type = "sdfile",
    .mount 	= sdfile_mount,
    .fopen 	= sdfile_open,
    .fread 	= sdfile_read,
    .fwrite = sdfile_write,
    .fseek 	= sdfile_seek,
    .flen 	= sdfile_len,
    .fpos 	= sdfile_pos,
    .fclose = sdfile_close,
#if SDFILE_STORAGE
    .fscan  = sdfile_scan,
    .fsel   = sdfile_sel,
    .fscan_release = sdfile_scan_release,
    .fget_attr = sdfile_get_attr,
    .ioctl  = sdfile_ioctl,
#else
    .fscan  = NULL,
    .fsel   = NULL,
    .fscan_release = NULL,
    .fget_attr = NULL,
    .ioctl  = NULL,
#endif /* #if SDFILE_STORAGE */
    .fdelete = sdfile_delete,
    .fget_name = sdfile_get_name,
    .fget_attrs = sdfile_get_attrs,
};


#if NOR_SDFILE_ENABLE
REGISTER_VFS_OPERATIONS(nor_sdfile_vfs_ops) = {
    .fs_type = "nor_sdfile",
    .mount 	= nor_sdfile_mount,
    .fopen 	= nor_sdfile_open,
    .fread 	= nor_sdfile_read,
    .fwrite = sdfile_write,
    .fseek 	= sdfile_seek,
    .flen 	= sdfile_len,
    .fpos 	= sdfile_pos,
    .fclose = sdfile_close,
#if SDFILE_STORAGE
    .fscan  = sdfile_scan,
    .fsel   = sdfile_sel,
    .fscan_release = sdfile_scan_release,
    .fget_attr = sdfile_get_attr,
    .ioctl  = sdfile_ioctl,
#else
    .fscan  = NULL,
    .fsel   = NULL,
    .fscan_release = NULL,
    .fget_attr = NULL,
    .ioctl  = NULL,
#endif /* #if SDFILE_STORAGE */
    .fget_name = sdfile_get_name,
    .fget_attrs = sdfile_get_attrs,
};
#endif


#else

/*
   SDFILE文件路径: mnt/sdfile/app/文件名
   SDFILE文件路径: mnt/sdfile/res/文件名
 */
SDFILE *sdfile_open(const char *path, const char *mode)
{
    int ret;
    const char *path_new = path;
    struct sdfile_dir dir;
    char name[16 + 1] = {0};

    if (path == NULL) {
        return NULL;
    }

    SDFILE *pfile = (SDFILE *)malloc(sizeof(SDFILE));

    if (!pfile) {
        return NULL;
    }
    memset(pfile, 0, sizeof(SDFILE));

    path_new = __sdfile_path_get_name(path_new, name);
    path_new = __sdfile_path_get_name(path_new, name);

    if (!strcmp(name, "SDFILE")) {
        path_new = __sdfile_path_get_name(path_new, name);
        if (!strcmp(name, "APP")) {
            ret = sdfile_open_app_file(pfile, path_new);
        } else if (!strcmp(name, "RES")) {
            ret = sdfile_open_res_file(pfile, path_new);
        } else {
            log_error("sdfile not support part %s", name);
            goto _err_exit;
        }
        if (ret == SDFILE_SUSS) {
            //log_info("Open [%s] Succ (^_^)", path);
            return pfile;
        }
    } else {
        log_error("not sdfile disk");
    }

_err_exit:
    log_debug("Open 0x%x, [%s] Fail! (>_<)", path, path);
    free(pfile);
    return NULL;
}

int sdfile_read(SDFILE *fp, void *buf, u32 len)
{
    u32 remain_len;
    u32 rlen;

    if (fp == NULL) {
        return 0;
    }

    remain_len = fp->head.len - fp->fptr;
    rlen = len;

    if (remain_len < len) {
        rlen = remain_len;
    }

    //*buf = (u8*)(fp->fptr + fp->head.addr);

    memcpy((u8 *)buf, (u8 *)(fp->fptr + fp->head.addr), len);

    fp->fptr += rlen;

    return rlen;
}

int sdfile_seek(SDFILE *fp, u32 offset, u32 fromwhere)
{

    switch (fromwhere) {
    case SEEK_SET:
        fp->fptr = offset;
        break;
    case SEEK_CUR:
        fp->fptr += offset;
        break;
    case SEEK_END:
        fp->fptr = fp->head.len - offset;
        break;
    }

    return 0;
}

int sdfile_get_flash_head(void)
{
    struct flash_head flashhead = {0};
    u16 local_flash_key = get_chip_id();
    norflash_origin_read((u8 *)&flashhead, 0, sizeof(flashhead));
    decode_data_by_user_key_in_sdfile(local_flash_key, (u8 *)&flashhead, sizeof(flashhead), 0, sizeof(flashhead));
    /* put_buf(&flashhead, sizeof(flashhead)); */
    if (flashhead.crc != CRC16((u8 *)&flashhead.size4burner, sizeof(flashhead) - sizeof(flashhead.crc))) {
        y_printf("\n >>>[test]:func = %s,line= %d\n", __FUNCTION__, __LINE__);
        return 1;
    }
    /* r_printf(">>>[test]:erase block = 0x%x\n", flashhead.align); */
    return flashhead.align;
}

int sdfile_write(SDFILE *fp, void *buf, u32 len)
{
    u32 remain_len;
    u32 wlen;
    u32 waddr;
    int ret;

    if (fp == NULL) {
        return 0;
    }

    remain_len = fp->head.len - fp->fptr;
    wlen = len;

    if (remain_len < len) {
        wlen = remain_len;
    }

    waddr = fp->fptr + fp->head.addr; 			//cpu logic addr
    waddr = sdfile_cpu_addr2flash_addr(waddr);  	//flash addr

    ret = sdfile_write_area_check(buf, waddr, len);  //flash addr
    if (ret) {
        return ret;  //由上层负责擦除
    }

    ret = norflash_write(NULL, (u8 *)buf, wlen, waddr);
    if (ret == wlen) {
        fp->fptr += wlen;
    }

    return ret;
}

int sdfile_close(SDFILE *fp)
{
    if (fp) {
        free(fp);
    }

    return 0;
}

int sdfile_len(SDFILE *fp)
{
    if (fp) {
        return fp->head.len;
    }

    return 0;
}

int sdfile_pos(SDFILE *fp)
{
    if (fp) {
        return fp->fptr;
    }

    return 0;
}

int sdfile_get_name(SDFILE *fp, u8 *name, int len)
{
    if (!fp) {
        return 0;
    }

    if (len > 16) {
        len = 16;
    }
    memcpy(name, fp->head.name, len);

    return len;
}


int sdfile_get_attrs(SDFILE *fp, struct vfs_attr *attr)
{
    if (!fp) {
        return 0;
    }

    /* attr->attr = fp->head.attr; */
    if ((fp->head.attr & SDFILE_FILE_ATTR_TYPE_MASK) == SDFILE_FILE_ATTR_DIR) {
        attr->attr |= F_ATTR_DIR;
    } else if ((fp->head.attr & SDFILE_FILE_ATTR_TYPE_MASK) == SDFILE_FILE_ATTR_REG) {
        /* attr->attr |= F_ATTR_RO; */
    }

    attr->fsize = fp->head.len;
    attr->sclust = fp->head.addr;
    return 0;
}

#endif /* #if (VFS_ENABLE == 1) */


u32 sdfile_get_disk_capacity(void)
{
    u32 cap = 0;
    norflash_ioctl(NULL, IOCTL_GET_CAPACITY, (u32)&cap);

    return cap;
}

int sdfile_delete_data(SDFILE *fp)
{
    u32 addr, len;
    bool ret;

    if (fp == NULL) {
        return 0;
    }

    addr = fp->head.addr; 			//cpu logic addr
    addr = sdfile_cpu_addr2flash_addr(addr);  	//flash addr
    len = fp->head.len;
    ret =  sfc_erase_zone(addr, len);
    if (ret == false) {
        log_e("erase error!!!!!!!!!!!!");
        return 0;
    }

    return 1;
}

struct jlfs_file_head {
    u16 head_crc;
    u16 data_crc;
    u32 addr;
    u32 len;
    u8 attr;
    u8 res;
    u16 index;
    char name[16];
};

u32 get_isd_config(const char *key, void *value)
{
    u32 offset = 0;
    u32 flash_size = 0;
    norflash_ioctl(NULL, IOCTL_GET_CAPACITY, (u32)&flash_size);

    u8 *ptr = (u8 *)sdfile_flash_addr2cpu_addr(flash_size);
    struct 	jlfs_file_head ini_file;
    memcpy(&ini_file, ptr + 32 + 32 * 1, 32);
    doe(0xffff, &ini_file, 32, 0);
    ptr = sdfile_flash_addr2cpu_addr(flash_size + ini_file.addr);

    printf("\nFind %s key >>>\n", key);
    u8 item_len = 0;
    u32 skip_len = 0;
    u32 tmp_offset = 0;

    offset = 0x22;
    tmp_offset = offset;
    char temp_key[64] ;
    while (1) {
        memcpy(&item_len, ptr + offset, 1);
        if (item_len == 0xff || item_len == 0) {
            break;
        }
        offset ++;

        memcpy(temp_key, ptr + offset, sizeof(temp_key));

        skip_len = 1 + strlen(temp_key);
        /* printf("item_len:%d %d  %x %s\n", item_len, skip_len, offset, temp_key); */

        offset += skip_len;
        if (strcmp(temp_key, key) == 0) {
            memcpy(value, ptr + offset, item_len);
            printf_buf(value, item_len);
            return item_len;
        }
        offset += item_len;
    }
    return 0;
}





#endif 	/* #if (USE_SDFILE_NEW == 1) */

